home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / Net / SMTP.php < prev    next >
PHP Script  |  2004-10-01  |  29KB  |  971 lines

  1. <?php
  2. /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Chuck Hagenbuch <chuck@horde.org>                           |
  17. // |          Jon Parise <jon@php.net>                                    |
  18. // |          Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar>      |
  19. // +----------------------------------------------------------------------+
  20.  
  21. require_once 'PEAR.php';
  22. require_once 'Net/Socket.php';
  23.  
  24. /**
  25.  * Provides an implementation of the SMTP protocol using PEAR's
  26.  * Net_Socket:: class.
  27.  *
  28.  * @package Net_SMTP
  29.  * @author  Chuck Hagenbuch <chuck@horde.org>
  30.  * @author  Jon Parise <jon@php.net>
  31.  * @author  Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar>
  32.  *
  33.  * @example basic.php   A basic implementation of the Net_SMTP package.
  34.  */
  35. class Net_SMTP
  36. {
  37.     /**
  38.      * The server to connect to.
  39.      * @var string
  40.      * @access public
  41.      */
  42.     var $host = 'localhost';
  43.  
  44.     /**
  45.      * The port to connect to.
  46.      * @var int
  47.      * @access public
  48.      */
  49.     var $port = 25;
  50.  
  51.     /**
  52.      * The value to give when sending EHLO or HELO.
  53.      * @var string
  54.      * @access public
  55.      */
  56.     var $localhost = 'localhost';
  57.  
  58.     /**
  59.      * List of supported authentication methods, in preferential order.
  60.      * @var array
  61.      * @access public
  62.      */
  63.     var $auth_methods = array('DIGEST-MD5', 'CRAM-MD5', 'LOGIN', 'PLAIN');
  64.  
  65.     /**
  66.      * Should debugging output be enabled?
  67.      * @var boolean
  68.      * @access private
  69.      */
  70.     var $_debug = false;
  71.  
  72.     /**
  73.      * The socket resource being used to connect to the SMTP server.
  74.      * @var resource
  75.      * @access private
  76.      */
  77.     var $_socket = null;
  78.  
  79.     /**
  80.      * The most recent server response code.
  81.      * @var int
  82.      * @access private
  83.      */
  84.     var $_code = -1;
  85.  
  86.     /**
  87.      * The most recent server response arguments.
  88.      * @var array
  89.      * @access private
  90.      */
  91.     var $_arguments = array();
  92.  
  93.     /**
  94.      * Stores detected features of the SMTP server.
  95.      * @var array
  96.      * @access private
  97.      */
  98.     var $_esmtp = array();
  99.  
  100.     /**
  101.      * Instantiates a new Net_SMTP object, overriding any defaults
  102.      * with parameters that are passed in.
  103.      *
  104.      * @param string The server to connect to.
  105.      * @param int The port to connect to.
  106.      * @param string The value to give when sending EHLO or HELO.
  107.      *
  108.      * @access  public
  109.      * @since   1.0
  110.      */
  111.     function Net_SMTP($host = null, $port = null, $localhost = null)
  112.     {
  113.         if (isset($host)) $this->host = $host;
  114.         if (isset($port)) $this->port = $port;
  115.         if (isset($localhost)) $this->localhost = $localhost;
  116.  
  117.         $this->_socket = new Net_Socket();
  118.  
  119.         /*
  120.          * Include the Auth_SASL package.  If the package is not available,
  121.          * we disable the authentication methods that depend upon it.
  122.          */
  123.         if ((@include_once 'Auth/SASL.php') === false) {
  124.             $pos = array_search('DIGEST-MD5', $this->auth_methods);
  125.             unset($this->auth_methods[$pos]);
  126.             $pos = array_search('CRAM-MD5', $this->auth_methods);
  127.             unset($this->auth_methods[$pos]);
  128.         }
  129.     }
  130.  
  131.     /**
  132.      * Set the value of the debugging flag.
  133.      *
  134.      * @param   boolean $debug      New value for the debugging flag.
  135.      *
  136.      * @access  public
  137.      * @since   1.1.0
  138.      */
  139.     function setDebug($debug)
  140.     {
  141.         $this->_debug = $debug;
  142.     }
  143.  
  144.     /**
  145.      * Send the given string of data to the server.
  146.      *
  147.      * @param   string  $data       The string of data to send.
  148.      *
  149.      * @return  mixed   True on success or a PEAR_Error object on failure.
  150.      *
  151.      * @access  private
  152.      * @since   1.1.0
  153.      */
  154.     function _send($data)
  155.     {
  156.         if ($this->_debug) {
  157.             echo "DEBUG: Send: $data\n";
  158.         }
  159.  
  160.         if (PEAR::isError($error = $this->_socket->write($data))) {
  161.             return new PEAR_Error('Failed to write to socket: ' .
  162.                                   $error->getMessage());
  163.         }
  164.  
  165.         return true;
  166.     }
  167.  
  168.     /**
  169.      * Send a command to the server with an optional string of arguments.
  170.      * A carriage return / linefeed (CRLF) sequence will be appended to each
  171.      * command string before it is sent to the SMTP server.
  172.      *
  173.      * @param   string  $command    The SMTP command to send to the server.
  174.      * @param   string  $args       A string of optional arguments to append
  175.      *                              to the command.
  176.      *
  177.      * @return  mixed   The result of the _send() call.
  178.      *
  179.      * @access  private
  180.      * @since   1.1.0
  181.      */
  182.     function _put($command, $args = '')
  183.     {
  184.         if (!empty($args)) {
  185.             return $this->_send($command . ' ' . $args . "\r\n");
  186.         }
  187.  
  188.         return $this->_send($command . "\r\n");
  189.     }
  190.  
  191.     /**
  192.      * Read a reply from the SMTP server.  The reply consists of a response
  193.      * code and a response message.
  194.      *
  195.      * @param   mixed   $valid      The set of valid response codes.  These
  196.      *                              may be specified as an array of integer
  197.      *                              values or as a single integer value.
  198.      *
  199.      * @return  mixed   True if the server returned a valid response code or
  200.      *                  a PEAR_Error object is an error condition is reached.
  201.      *
  202.      * @access  private
  203.      * @since   1.1.0
  204.      *
  205.      * @see     getResponse
  206.      */
  207.     function _parseResponse($valid)
  208.     {
  209.         $this->_code = -1;
  210.         $this->_arguments = array();
  211.  
  212.         while ($line = $this->_socket->readLine()) {
  213.             if ($this->_debug) {
  214.                 echo "DEBUG: Recv: $line\n";
  215.             }
  216.  
  217.             /* If we receive an empty line, the connection has been closed. */
  218.             if (empty($line)) {
  219.                 $this->disconnect();
  220.                 return new PEAR_Error("Connection was unexpectedly closed");
  221.             }
  222.  
  223.             /* Read the code and store the rest in the arguments array. */
  224.             $code = substr($line, 0, 3);
  225.             $this->_arguments[] = trim(substr($line, 4));
  226.  
  227.             /* Check the syntax of the response code. */
  228.             if (is_numeric($code)) {
  229.                 $this->_code = (int)$code;
  230.             } else {
  231.                 $this->_code = -1;
  232.                 break;
  233.             }
  234.  
  235.             /* If this is not a multiline response, we're done. */
  236.             if (substr($line, 3, 1) != '-') {
  237.                 break;
  238.             }
  239.         }
  240.  
  241.         /* Compare the server's response code with the valid code. */
  242.         if (is_int($valid) && ($this->_code === $valid)) {
  243.             return true;
  244.         }
  245.  
  246.         /* If we were given an array of valid response codes, check each one. */
  247.         if (is_array($valid)) {
  248.             foreach ($valid as $valid_code) {
  249.                 if ($this->_code === $valid_code) {
  250.                     return true;
  251.                 }
  252.             }
  253.         }
  254.  
  255.         return new PEAR_Error("Invalid response code received from server");
  256.     }
  257.  
  258.     /**
  259.      * Return a 2-tuple containing the last response from the SMTP server.
  260.      *
  261.      * @return  array   A two-element array: the first element contains the
  262.      *                  response code as an integer and the second element
  263.      *                  contains the response's arguments as a string.
  264.      *
  265.      * @access  public
  266.      * @since   1.1.0
  267.      */
  268.     function getResponse()
  269.     {
  270.         return array($this->_code, join("\n", $this->_arguments));
  271.     }
  272.  
  273.     /**
  274.      * Attempt to connect to the SMTP server.
  275.      *
  276.      * @param   int     $timeout    The timeout value (in seconds) for the
  277.      *                              socket connection.
  278.      * @param   bool    $persistent Should a persistent socket connection
  279.      *                              be used?
  280.      *
  281.      * @return mixed Returns a PEAR_Error with an error message on any
  282.      *               kind of failure, or true on success.
  283.      * @access public
  284.      * @since  1.0
  285.      */
  286.     function connect($timeout = null, $persistent = false)
  287.     {
  288.         $result = $this->_socket->connect($this->host, $this->port,
  289.                                           $persistent, $timeout);
  290.         if (PEAR::isError($result)) {
  291.             return new PEAR_Error('Failed to connect socket: ' .
  292.                                   $result->getMessage());
  293.         }
  294.  
  295.         if (PEAR::isError($error = $this->_parseResponse(220))) {
  296.             return $error;
  297.         }
  298.         if (PEAR::isError($error = $this->_negotiate())) {
  299.             return $error;
  300.         }
  301.  
  302.         return true;
  303.     }
  304.  
  305.     /**
  306.      * Attempt to disconnect from the SMTP server.
  307.      *
  308.      * @return mixed Returns a PEAR_Error with an error message on any
  309.      *               kind of failure, or true on success.
  310.      * @access public
  311.      * @since  1.0
  312.      */
  313.     function disconnect()
  314.     {
  315.         if (PEAR::isError($error = $this->_put('QUIT'))) {
  316.             return $error;
  317.         }
  318.         if (PEAR::isError($error = $this->_parseResponse(221))) {
  319.             return $error;
  320.         }
  321.         if (PEAR::isError($error = $this->_socket->disconnect())) {
  322.             return new PEAR_Error('Failed to disconnect socket: ' .
  323.                                   $error->getMessage());
  324.         }
  325.  
  326.         return true;
  327.     }
  328.  
  329.     /**
  330.      * Attempt to send the EHLO command and obtain a list of ESMTP
  331.      * extensions available, and failing that just send HELO.
  332.      *
  333.      * @return mixed Returns a PEAR_Error with an error message on any
  334.      *               kind of failure, or true on success.
  335.      *
  336.      * @access private
  337.      * @since  1.1.0
  338.      */
  339.     function _negotiate()
  340.     {
  341.         if (PEAR::isError($error = $this->_put('EHLO', $this->localhost))) {
  342.             return $error;
  343.         }
  344.  
  345.         if (PEAR::isError($this->_parseResponse(250))) {
  346.             /* If we receive a 503 response, we're already authenticated. */
  347.             if ($this->_code === 503) {
  348.                 return true;
  349.             }
  350.  
  351.             /* If the EHLO failed, try the simpler HELO command. */
  352.             if (PEAR::isError($error = $this->_put('HELO', $this->localhost))) {
  353.                 return $error;
  354.             }
  355.             if (PEAR::isError($this->_parseResponse(250))) {
  356.                 return new PEAR_Error('HELO was not accepted: ', $this->_code);
  357.             }
  358.  
  359.             return true;
  360.         }
  361.  
  362.         foreach ($this->_arguments as $argument) {
  363.             $verb = strtok($argument, ' ');
  364.             $arguments = substr($argument, strlen($verb) + 1,
  365.                                 strlen($argument) - strlen($verb) - 1);
  366.             $this->_esmtp[$verb] = $arguments;
  367.         }
  368.  
  369.         return true;
  370.     }
  371.  
  372.     /**
  373.      * Returns the name of the best authentication method that the server
  374.      * has advertised.
  375.      *
  376.      * @return mixed    Returns a string containing the name of the best
  377.      *                  supported authentication method or a PEAR_Error object
  378.      *                  if a failure condition is encountered.
  379.      * @access private
  380.      * @since  1.1.0
  381.      */
  382.     function _getBestAuthMethod()
  383.     {
  384.         $available_methods = explode(' ', $this->_esmtp['AUTH']);
  385.  
  386.         foreach ($this->auth_methods as $method) {
  387.             if (in_array($method, $available_methods)) {
  388.                 return $method;
  389.             }
  390.         }
  391.  
  392.         return new PEAR_Error('No supported authentication methods');
  393.     }
  394.  
  395.     /**
  396.      * Attempt to do SMTP authentication.
  397.      *
  398.      * @param string The userid to authenticate as.
  399.      * @param string The password to authenticate with.
  400.      * @param string The requested authentication method.  If none is
  401.      *               specified, the best supported method will be used.
  402.      *
  403.      * @return mixed Returns a PEAR_Error with an error message on any
  404.      *               kind of failure, or true on success.
  405.      * @access public
  406.      * @since  1.0
  407.      */
  408.     function auth($uid, $pwd , $method = '')
  409.     {
  410.         if (empty($this->_esmtp['AUTH'])) {
  411.             return new PEAR_Error('SMTP server does no support authentication');
  412.         }
  413.  
  414.         /*
  415.          * If no method has been specified, get the name of the best supported
  416.          * method advertised by the SMTP server.
  417.          */
  418.         if (empty($method)) {
  419.             if (PEAR::isError($method = $this->_getBestAuthMethod())) {
  420.                 /* Return the PEAR_Error object from _getBestAuthMethod(). */
  421.                 return $method;
  422.             }
  423.         } else {
  424.             $method = strtoupper($method);
  425.             if (!in_array($method, $this->auth_methods)) {
  426.                 return new PEAR_Error("$method is not a supported authentication method");
  427.             }
  428.         }
  429.  
  430.         switch ($method) {
  431.             case 'DIGEST-MD5':
  432.                 $result = $this->_authDigest_MD5($uid, $pwd);
  433.                 break;
  434.             case 'CRAM-MD5':
  435.                 $result = $this->_authCRAM_MD5($uid, $pwd);
  436.                 break;
  437.             case 'LOGIN':
  438.                 $result = $this->_authLogin($uid, $pwd);
  439.                 break;
  440.             case 'PLAIN':
  441.                 $result = $this->_authPlain($uid, $pwd);
  442.                 break;
  443.             default:
  444.                 $result = new PEAR_Error("$method is not a supported authentication method");
  445.                 break;
  446.         }
  447.  
  448.         /* If an error was encountered, return the PEAR_Error object. */
  449.         if (PEAR::isError($result)) {
  450.             return $result;
  451.         }
  452.  
  453.         /* RFC-2554 requires us to re-negotiate ESMTP after an AUTH. */
  454.         if (PEAR::isError($error = $this->_negotiate())) {
  455.             return $error;
  456.         }
  457.  
  458.         return true;
  459.     }
  460.  
  461.     /**
  462.      * Authenticates the user using the DIGEST-MD5 method.
  463.      *
  464.      * @param string The userid to authenticate as.
  465.      * @param string The password to authenticate with.
  466.      *
  467.      * @return mixed Returns a PEAR_Error with an error message on any
  468.      *               kind of failure, or true on success.
  469.      * @access private
  470.      * @since  1.1.0
  471.      */
  472.     function _authDigest_MD5($uid, $pwd)
  473.     {
  474.         if (PEAR::isError($error = $this->_put('AUTH', 'DIGEST-MD5'))) {
  475.             return $error;
  476.         }
  477.         /* 334: Continue authentication request */
  478.         if (PEAR::isError($error = $this->_parseResponse(334))) {
  479.             /* 503: Error: already authenticated */
  480.             if ($this->_code === 503) {
  481.                 return true;
  482.             }
  483.             return $error;
  484.         }
  485.  
  486.         $challenge = base64_decode($this->_arguments[0]);
  487.         $digest = &Auth_SASL::factory('digestmd5');
  488.         $auth_str = base64_encode($digest->getResponse($uid, $pwd, $challenge,
  489.                                                        $this->host, "smtp"));
  490.  
  491.         if (PEAR::isError($error = $this->_put($auth_str))) {
  492.             return $error;
  493.         }
  494.         /* 334: Continue authentication request */
  495.         if (PEAR::isError($error = $this->_parseResponse(334))) {
  496.             return $error;
  497.         }
  498.  
  499.         /*
  500.          * We don't use the protocol's third step because SMTP doesn't allow
  501.          * subsequent authentication, so we just silently ignore it.
  502.          */
  503.         if (PEAR::isError($error = $this->_put(' '))) {
  504.             return $error;
  505.         }
  506.         /* 235: Authentication successful */
  507.         if (PEAR::isError($error = $this->_parseResponse(235))) {
  508.             return $error;
  509.         }
  510.     }
  511.  
  512.     /**
  513.      * Authenticates the user using the CRAM-MD5 method.
  514.      *
  515.      * @param string The userid to authenticate as.
  516.      * @param string The password to authenticate with.
  517.      *
  518.      * @return mixed Returns a PEAR_Error with an error message on any
  519.      *               kind of failure, or true on success.
  520.      * @access private
  521.      * @since  1.1.0
  522.      */
  523.     function _authCRAM_MD5($uid, $pwd)
  524.     {
  525.         if (PEAR::isError($error = $this->_put('AUTH', 'CRAM-MD5'))) {
  526.             return $error;
  527.         }
  528.         /* 334: Continue authentication request */
  529.         if (PEAR::isError($error = $this->_parseResponse(334))) {
  530.             /* 503: Error: already authenticated */
  531.             if ($this->_code === 503) {
  532.                 return true;
  533.             }
  534.             return $error;
  535.         }
  536.  
  537.         $challenge = base64_decode($this->_arguments[0]);
  538.         $cram = &Auth_SASL::factory('crammd5');
  539.         $auth_str = base64_encode($cram->getResponse($uid, $pwd, $challenge));
  540.  
  541.         if (PEAR::isError($error = $this->_put($auth_str))) {
  542.             return $error;
  543.         }
  544.  
  545.         /* 235: Authentication successful */
  546.         if (PEAR::isError($error = $this->_parseResponse(235))) {
  547.             return $error;
  548.         }
  549.     }
  550.  
  551.     /**
  552.      * Authenticates the user using the LOGIN method.
  553.      *
  554.      * @param string The userid to authenticate as.
  555.      * @param string The password to authenticate with.
  556.      *
  557.      * @return mixed Returns a PEAR_Error with an error message on any
  558.      *               kind of failure, or true on success.
  559.      * @access private
  560.      * @since  1.1.0
  561.      */
  562.     function _authLogin($uid, $pwd)
  563.     {
  564.         if (PEAR::isError($error = $this->_put('AUTH', 'LOGIN'))) { 
  565.             return $error;
  566.         }
  567.         /* 334: Continue authentication request */
  568.         if (PEAR::isError($error = $this->_parseResponse(334))) {
  569.             /* 503: Error: already authenticated */
  570.             if ($this->_code === 503) {
  571.                 return true;
  572.             }
  573.             return $error;
  574.         }
  575.  
  576.         if (PEAR::isError($error = $this->_put(base64_encode($uid)))) {
  577.             return $error;
  578.         }
  579.         /* 334: Continue authentication request */
  580.         if (PEAR::isError($error = $this->_parseResponse(334))) {
  581.             return $error;
  582.         }
  583.  
  584.         if (PEAR::isError($error = $this->_put(base64_encode($pwd)))) {
  585.             return $error;
  586.         }
  587.  
  588.         /* 235: Authentication successful */
  589.         if (PEAR::isError($error = $this->_parseResponse(235))) {
  590.             return $error;
  591.         }
  592.  
  593.         return true;
  594.     }
  595.  
  596.     /**
  597.      * Authenticates the user using the PLAIN method.
  598.      *
  599.      * @param string The userid to authenticate as.
  600.      * @param string The password to authenticate with.
  601.      *
  602.      * @return mixed Returns a PEAR_Error with an error message on any
  603.      *               kind of failure, or true on success.
  604.      * @access private
  605.      * @since  1.1.0
  606.      */
  607.     function _authPlain($uid, $pwd)
  608.     {
  609.         if (PEAR::isError($error = $this->_put('AUTH', 'PLAIN'))) {
  610.             return $error;
  611.         }
  612.         /* 334: Continue authentication request */
  613.         if (PEAR::isError($error = $this->_parseResponse(334))) {
  614.             /* 503: Error: already authenticated */
  615.             if ($this->_code === 503) {
  616.                 return true;
  617.             }
  618.             return $error;
  619.         }
  620.  
  621.         $auth_str = base64_encode(chr(0) . $uid . chr(0) . $pwd);
  622.  
  623.         if (PEAR::isError($error = $this->_put($auth_str))) {
  624.             return $error;
  625.         }
  626.  
  627.         /* 235: Authentication successful */
  628.         if (PEAR::isError($error = $this->_parseResponse(235))) {
  629.             return $error;
  630.         }
  631.  
  632.         return true;
  633.     }
  634.  
  635.     /**
  636.      * Send the HELO command.
  637.      *
  638.      * @param string The domain name to say we are.
  639.      *
  640.      * @return mixed Returns a PEAR_Error with an error message on any
  641.      *               kind of failure, or true on success.
  642.      * @access public
  643.      * @since  1.0
  644.      */
  645.     function helo($domain)
  646.     {
  647.         if (PEAR::isError($error = $this->_put('HELO', $domain))) {
  648.             return $error;
  649.         }
  650.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  651.             return $error;
  652.         }
  653.  
  654.         return true;
  655.     }
  656.  
  657.     /**
  658.      * Send the MAIL FROM: command.
  659.      *
  660.      * @param string The sender (reverse path) to set.
  661.      *
  662.      * @return mixed Returns a PEAR_Error with an error message on any
  663.      *               kind of failure, or true on success.
  664.      * @access public
  665.      * @since  1.0
  666.      */
  667.     function mailFrom($sender)
  668.     {
  669.         if (PEAR::isError($error = $this->_put('MAIL', "FROM:<$sender>"))) {
  670.             return $error;
  671.         }
  672.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  673.             return $error;
  674.         }
  675.  
  676.         return true;
  677.     }
  678.  
  679.     /**
  680.      * Send the RCPT TO: command.
  681.      *
  682.      * @param string The recipient (forward path) to add.
  683.      *
  684.      * @return mixed Returns a PEAR_Error with an error message on any
  685.      *               kind of failure, or true on success.
  686.      * @access public
  687.      * @since  1.0
  688.      */
  689.     function rcptTo($recipient)
  690.     {
  691.         if (PEAR::isError($error = $this->_put('RCPT', "TO:<$recipient>"))) {
  692.             return $error;
  693.         }
  694.         if (PEAR::isError($error = $this->_parseResponse(array(250, 251)))) {
  695.             return $error;
  696.         }
  697.  
  698.         return true;
  699.     }
  700.  
  701.     /**
  702.      * Quote the data so that it meets SMTP standards.
  703.      *
  704.      * This is provided as a separate public function to facilitate easier
  705.      * overloading for the cases where it is desirable to customize the
  706.      * quoting behavior.
  707.      *
  708.      * @param string The message text to quote.  The string must be passed
  709.      *               by reference, and the text will be modified in place.
  710.      *
  711.      * @access public
  712.      * @since  1.2
  713.      */
  714.     function quotedata(&$data)
  715.     {
  716.         /*
  717.          * Change Unix (\n) and Mac (\r) linefeeds into Internet-standard CRLF
  718.          * (\r\n) linefeeds.
  719.          */
  720.         $data = preg_replace("/([^\r]{1})\n/", "\\1\r\n", $data);
  721.         $data = preg_replace("/\n\n/", "\n\r\n", $data);
  722.  
  723.         /*
  724.          * Because a single leading period (.) signifies an end to the data,
  725.          * legitimate leading periods need to be "doubled" (e.g. '..').
  726.          */
  727.         $data = preg_replace("/\n\./", "\n..", $data);
  728.     }
  729.  
  730.     /**
  731.      * Send the DATA command.
  732.      *
  733.      * @param string The message body to send.
  734.      *
  735.      * @return mixed Returns a PEAR_Error with an error message on any
  736.      *               kind of failure, or true on success.
  737.      * @access public
  738.      * @since  1.0
  739.      */
  740.     function data($data)
  741.     {
  742.         /*
  743.          * RFC 1870, section 3, subsection 3 states "a value of zero indicates
  744.          * that no fixed maximum message size is in force".  Furthermore, it
  745.          * says that if "the parameter is omitted no information is conveyed
  746.          * about the server's fixed maximum message size".
  747.          */
  748.         if (isset($this->_esmtp['SIZE']) && ($this->_esmtp['SIZE'] > 0)) {
  749.             if (strlen($data) >= $this->_esmtp['SIZE']) {
  750.                 $this->disconnect();
  751.                 return new PEAR_Error('Message size excedes the server limit');
  752.             }
  753.         }
  754.  
  755.         /* Quote the data based on the SMTP standards. */
  756.         $this->quotedata($data);
  757.  
  758.         if (PEAR::isError($error = $this->_put('DATA'))) {
  759.             return $error;
  760.         }
  761.         if (PEAR::isError($error = $this->_parseResponse(354))) {
  762.             return $error;
  763.         }
  764.  
  765.         if (PEAR::isError($this->_send($data . "\r\n.\r\n"))) {
  766.             return new PEAR_Error('write to socket failed');
  767.         }
  768.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  769.             return $error;
  770.         }
  771.  
  772.         return true;
  773.     }
  774.  
  775.     /**
  776.      * Send the SEND FROM: command.
  777.      *
  778.      * @param string The reverse path to send.
  779.      *
  780.      * @return mixed Returns a PEAR_Error with an error message on any
  781.      *               kind of failure, or true on success.
  782.      * @access public
  783.      * @since  1.2.6
  784.      */
  785.     function sendFrom($path)
  786.     {
  787.         if (PEAR::isError($error = $this->_put('SEND', "FROM:<$path>"))) {
  788.             return $error;
  789.         }
  790.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  791.             return $error;
  792.         }
  793.  
  794.         return true;
  795.     }
  796.  
  797.     /**
  798.      * Backwards-compatibility wrapper for sendFrom().
  799.      *
  800.      * @param string The reverse path to send.
  801.      *
  802.      * @return mixed Returns a PEAR_Error with an error message on any
  803.      *               kind of failure, or true on success.
  804.      *
  805.      * @access      public
  806.      * @since       1.0
  807.      * @deprecated  1.2.6
  808.      */
  809.     function send_from($path)
  810.     {
  811.         return sendFrom($path);
  812.     }
  813.  
  814.     /**
  815.      * Send the SOML FROM: command.
  816.      *
  817.      * @param string The reverse path to send.
  818.      *
  819.      * @return mixed Returns a PEAR_Error with an error message on any
  820.      *               kind of failure, or true on success.
  821.      * @access public
  822.      * @since  1.2.6
  823.      */
  824.     function somlFrom($path)
  825.     {
  826.         if (PEAR::isError($error = $this->_put('SOML', "FROM:<$path>"))) {
  827.             return $error;
  828.         }
  829.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  830.             return $error;
  831.         }
  832.  
  833.         return true;
  834.     }
  835.  
  836.     /**
  837.      * Backwards-compatibility wrapper for somlFrom().
  838.      *
  839.      * @param string The reverse path to send.
  840.      *
  841.      * @return mixed Returns a PEAR_Error with an error message on any
  842.      *               kind of failure, or true on success.
  843.      *
  844.      * @access      public
  845.      * @since       1.0
  846.      * @deprecated  1.2.6
  847.      */
  848.     function soml_from($path)
  849.     {
  850.         return somlFrom($path);
  851.     }
  852.  
  853.     /**
  854.      * Send the SAML FROM: command.
  855.      *
  856.      * @param string The reverse path to send.
  857.      *
  858.      * @return mixed Returns a PEAR_Error with an error message on any
  859.      *               kind of failure, or true on success.
  860.      * @access public
  861.      * @since  1.2.6
  862.      */
  863.     function samlFrom($path)
  864.     {
  865.         if (PEAR::isError($error = $this->_put('SAML', "FROM:<$path>"))) {
  866.             return $error;
  867.         }
  868.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  869.             return $error;
  870.         }
  871.  
  872.         return true;
  873.     }
  874.  
  875.     /**
  876.      * Backwards-compatibility wrapper for samlFrom().
  877.      *
  878.      * @param string The reverse path to send.
  879.      *
  880.      * @return mixed Returns a PEAR_Error with an error message on any
  881.      *               kind of failure, or true on success.
  882.      *
  883.      * @access      public
  884.      * @since       1.0
  885.      * @deprecated  1.2.6
  886.      */
  887.     function saml_from($path)
  888.     {
  889.         return samlFrom($path);
  890.     }
  891.  
  892.     /**
  893.      * Send the RSET command.
  894.      *
  895.      * @return mixed Returns a PEAR_Error with an error message on any
  896.      *               kind of failure, or true on success.
  897.      * @access public
  898.      * @since  1.0
  899.      */
  900.     function rset()
  901.     {
  902.         if (PEAR::isError($error = $this->_put('RSET'))) {
  903.             return $error;
  904.         }
  905.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  906.             return $error;
  907.         }
  908.  
  909.         return true;
  910.     }
  911.  
  912.     /**
  913.      * Send the VRFY command.
  914.      *
  915.      * @param string The string to verify
  916.      *
  917.      * @return mixed Returns a PEAR_Error with an error message on any
  918.      *               kind of failure, or true on success.
  919.      * @access public
  920.      * @since  1.0
  921.      */
  922.     function vrfy($string)
  923.     {
  924.         /* Note: 251 is also a valid response code */
  925.         if (PEAR::isError($error = $this->_put('VRFY', $string))) {
  926.             return $error;
  927.         }
  928.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  929.             return $error;
  930.         }
  931.  
  932.         return true;
  933.     }
  934.  
  935.     /**
  936.      * Send the NOOP command.
  937.      *
  938.      * @return mixed Returns a PEAR_Error with an error message on any
  939.      *               kind of failure, or true on success.
  940.      * @access public
  941.      * @since  1.0
  942.      */
  943.     function noop()
  944.     {
  945.         if (PEAR::isError($error = $this->_put('NOOP'))) {
  946.             return $error;
  947.         }
  948.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  949.             return $error;
  950.         }
  951.  
  952.         return true;
  953.     }
  954.  
  955.     /**
  956.      * Backwards-compatibility method.  identifySender()'s functionality is
  957.      * now handled internally.
  958.      *
  959.      * @return  boolean     This method always return true.
  960.      *
  961.      * @access  public
  962.      * @since   1.0
  963.      */
  964.     function identifySender()
  965.     {
  966.         return true;
  967.     }
  968. }
  969.  
  970. ?>
  971.